using System;
using System.Collections.Generic;
using System.Text;
using it.mintlab.desktopnet.mintar;
using Newtonsoft.Json;
using System.Reflection;
using System.Collections;
using System.IO;

namespace it.mintlab.desktopnet.restlib
{
    public static class JSONModelUtils
    {
        public static string getJSON(Model model)
        {
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);
            using (JsonWriter jsonWriter = new JsonTextWriter(sw))
            {
                jsonWriter.Formatting = Formatting.Indented;
                jsonWriter.WriteStartObject();
                
                //jsonWriter.WriteStartObject();
                
                //jsonWriter.WriteValue("Intel");
                //jsonWriter.WriteEndObject();

            

                PropertyInfo[] properties = model.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);   // for inheritance
                foreach (PropertyInfo pi in properties)
                {
                    //if any attribute is present
                    ModelAttr[] attrs = (ModelAttr[])pi.GetCustomAttributes(typeof(ModelAttr), false);
                    if (attrs.Length == 1)
                    {
                        jsonWriter.WritePropertyName(pi.Name);
                        object obj = pi.GetValue(model, null);
                        jsonWriter.WriteValue(obj);
                            //if (obj.GetType().Equals(typeof(bool)))
                            //    values += (((bool)obj) ? "'1'" : "'0'") + ", ";
                            //else if (obj.GetType().Equals(typeof(DateTime)))
                            //    values += "'" + String.Format("{0:s}", (DateTime)obj) + "', ";
                            //else if (obj.GetType().Equals(typeof(int)) || obj.GetType().Equals(typeof(decimal)))
                            //    values += obj.ToString().Replace(",", ".") + ", ";
                            //else
                            //    values += "'" + obj.ToString().Replace("'", "''") + "', ";//avoid sql injection
                            

                    }
                }

                jsonWriter.WriteEndObject();

            }
            return sb.ToString();
        }

        public static Model fillModel(string jsonObject, Type modelType)
        {
            Model model = null;

            try
            {
                ConstructorInfo constructor = modelType.GetConstructor(System.Type.EmptyTypes);
                model = (Model)constructor.Invoke(null);

                JsonReader reader = new JsonTextReader(new StringReader(jsonObject));
                while (reader.Read())
                {
                    if (reader.TokenType.Equals(JsonToken.StartObject))
                    {
                        reader.Read();
                        while (reader.TokenType.Equals(JsonToken.EndObject))
                        {
                            string propertyName = reader.Value.ToString();
                            PropertyInfo pi = modelType.GetProperty(propertyName);
                            reader.Read();
                            if (pi.PropertyType.Equals(typeof(bool)))
                            {
                                pi.SetValue(model, reader.Value.ToString().Equals("true") ? true : false, null);
                            }
                            else if (pi.PropertyType.Equals(typeof(DateTime)))
                            {
                                DateTime dt = DateTime.Parse(reader.Value.ToString());
                                pi.SetValue(model, dt, null);
                            }
                            else if (pi.PropertyType.Equals(typeof(int)))
                            {
                                pi.SetValue(model, int.Parse(reader.Value.ToString()), null);
                            }
                            else if (pi.PropertyType.Equals(typeof(decimal)))
                            {
                                pi.SetValue(model, decimal.Parse(reader.Value.ToString()), null);
                            }
                            else
                            {
                                pi.SetValue(model, reader.Value.ToString(), null);
                            }
                            reader.Read();
                        }
                    }
                }
                return model;
            }
            catch
            {
                return null;
            }
        }

        public static string getJSONArray(Array modelArray)
        {
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);
            using (JsonWriter jsonWriter = new JsonTextWriter(sw))
            {
                jsonWriter.Formatting = Formatting.Indented;
                jsonWriter.WriteStartArray();
                foreach (Object o in modelArray)
                    jsonWriter.WriteValue(getJSON((Model)o));
                jsonWriter.WriteEndArray();
            }
            return sb.ToString();
        }

        public static List<Model> fillModelList(string jsonArray, Type modelType)
        {
            List<Model> list = new List<Model>();
            
            try{
                JsonReader reader = new JsonTextReader(new StringReader(jsonArray));

                while (reader.Read())
                {
                    if (reader.TokenType.Equals(JsonToken.StartArray))
                    {
                        reader.Read();
                        while (reader.TokenType.Equals(JsonToken.EndArray))
                        {
                            ConstructorInfo constructor = modelType.GetConstructor(System.Type.EmptyTypes);
                            Model model = (Model)constructor.Invoke(null);

                            while (reader.Read())
                            {
                                if (reader.TokenType.Equals(JsonToken.StartObject))
                                {
                                    reader.Read();
                                    while (reader.TokenType.Equals(JsonToken.EndObject))
                                    {
                                        string propertyName = reader.Value.ToString();
                                        PropertyInfo pi = modelType.GetProperty(propertyName);
                                        reader.Read();
                                        if (pi.PropertyType.Equals(typeof(bool)))
                                        {
                                            pi.SetValue(model, reader.Value.ToString().Equals("true") ? true : false, null);
                                        }
                                        else if (pi.PropertyType.Equals(typeof(DateTime)))
                                        {
                                            DateTime dt = DateTime.Parse(reader.Value.ToString());
                                            pi.SetValue(model, dt, null);
                                        }
                                        else if (pi.PropertyType.Equals(typeof(int)))
                                        {
                                            pi.SetValue(model, int.Parse(reader.Value.ToString()), null);
                                        }
                                        else if (pi.PropertyType.Equals(typeof(decimal)))
                                        {
                                            pi.SetValue(model, decimal.Parse(reader.Value.ToString()), null);
                                        }
                                        else
                                        {
                                            pi.SetValue(model, reader.Value.ToString().ToString(), null);
                                        }
                                        reader.Read();
                                    }
                                }
                            }
                            list.Add(model);
                        }

                        return list;
                    }
                }

                return null;
            }
            catch
            {
                return null;
            }
        }
    }
}
